package com.freeheart.validation.constraintvalidators.in;


import com.freeheart.validation.constraints.In;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

import java.util.Collection;

/**
 * 实现对{@code com.freeheart.validation.constraints.In}注解校验的ConstraintValidator父类
 *
 * @author: EmperorHeart
 * @date: 2025/5/9 23:09
 * @description
 */
public abstract class AbstractInConstraintValidator implements ConstraintValidator<In, Object> {

    /**
     * 提供校验集合的InCollection实例
     */
    private InCollection inCollection;
    /**
     * 失败信息描述模板
     */
    private String msg;

    /**
     * 判断校验是否通过
     *
     * @param value   object to validate
     * @param context context in which the constraint is evaluated
     * @return true|false
     */
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        Collection<?> collection = inCollection.getCollection();
        if (collection.contains(value)) {
            return true;
        }
        validFail(context, handlerMsg(msg, value));
        return false;
    }

    /**
     * 将失败描述信息模板中的变量替换成实际值
     *
     * @param msg   失败描述信息模板
     * @param value 实际值
     * @return 校验失败描述信息
     */
    private String handlerMsg(String msg, Object value) {
        if (msg.contains("{e}")) {
            return msg.replaceAll("\\{e}", value.toString());
        }
        return msg;
    }

    /**
     * 初始化操作：用来保留注解中的属性值
     *
     * @param constraintAnnotation annotation instance for a given constraint declaration
     */
    @Override
    public void initialize(In constraintAnnotation) {
        this.inCollection = getInCollection(constraintAnnotation.value());
        this.msg = constraintAnnotation.message();
    }

    /**
     * 校验失败后填充描述信息进上下文
     *
     * @param context ConstraintValidatorContext
     * @param msg     校验失败描述信息
     */
    public void validFail(ConstraintValidatorContext context, String msg) {
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(msg).addConstraintViolation();
    }

    /**
     * 根据Class对象来获取一个InCollection实例。需要子类去实现
     *
     * @param clazz Class<? extends InCollection>
     * @return InCollection实例
     */
    protected abstract InCollection getInCollection(Class<? extends InCollection> clazz);
}
